{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "\n",
    "load_dotenv()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "LangChain 아이디를 입력합니다.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Owner 지정\n",
    "PROMPT_OWNER = \"teddynote\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 요약: Stuff Documents\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "prompt_title = \"summary-stuff-documents\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt_template = \"\"\"Please summarize the sentence according to the following REQUEST.\n",
    "REQUEST:\n",
    "1. Summarize the main points in bullet points.\n",
    "2. Each summarized sentence must start with an emoji that fits the meaning of the each sentence.\n",
    "3. Use various emojis to make the summary more interesting.\n",
    "4. DO NOT include any unnecessary information.\n",
    "\n",
    "CONTEXT:\n",
    "{context}\n",
    "\n",
    "SUMMARY:\"\n",
    "\"\"\"\n",
    "prompt = PromptTemplate.from_template(prompt_template)\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Map Prompt\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "prompt_title = \"map-prompt\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt_template = \"\"\"You are a helpful expert journalist in extracting the main themes from a GIVEN DOCUMENTS below.\n",
    "Please provide a comprehensive summary of the GIVEN DOCUMENTS in numbered list format. \n",
    "The summary should cover all the key points and main ideas presented in the original text, while also condensing the information into a concise and easy-to-understand format. \n",
    "Please ensure that the summary includes relevant details and examples that support the main ideas, while avoiding any unnecessary information or repetition. \n",
    "The length of the summary should be appropriate for the length and complexity of the original text, providing a clear and accurate overview without omitting any important information.\n",
    "\n",
    "GIVEN DOCUMENTS:\n",
    "{docs}\n",
    "\n",
    "FORMAT:\n",
    "1. main theme 1\n",
    "2. main theme 2\n",
    "3. main theme 3\n",
    "...\n",
    "\n",
    "CAUTION:\n",
    "- DO NOT list more than 5 main themes.\n",
    "\n",
    "Helpful Answer:\n",
    "\"\"\"\n",
    "prompt = PromptTemplate.from_template(prompt_template)\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reduce Prompt\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "prompt_title = \"reduce-prompt\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt_template = \"\"\"You are a helpful expert in summary writing.\n",
    "You are given numbered lists of summaries.\n",
    "Extract top 10 most important insights from the summaries.\n",
    "Then, write a summary of the insights in KOREAN.\n",
    "\n",
    "LIST OF SUMMARIES:\n",
    "{doc_summaries}\n",
    "\n",
    "Helpful Answer:\n",
    "\"\"\"\n",
    "prompt = PromptTemplate.from_template(prompt_template)\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "prompt_title = \"chain-of-density-reduce-korean\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt_template = \"\"\"You are a helpful expert in summary writing. You are given lists of summaries.\n",
    "Please sum up previously summarized sentences according to the following REQUEST.\n",
    "REQUEST:\n",
    "1. Summarize the main points in bullet points in KOREAN.\n",
    "2. Each summarized sentence must start with an emoji that fits the meaning of the each sentence.\n",
    "3. Use various emojis to make the summary more interesting.\n",
    "4. MOST IMPORTANT points should be organized at the top of the list.\n",
    "5. DO NOT include any unnecessary information.\n",
    "\n",
    "LIST OF SUMMARIES:\n",
    "{doc_summaries}\n",
    "\n",
    "Helpful Answer: \"\"\"\n",
    "prompt = PromptTemplate.from_template(prompt_template)\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Metadata Tagger\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "\n",
    "prompt_title = \"metadata-tagger\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt_template = \"\"\"Given the following product review, conduct a comprehensive analysis to extract key aspects mentioned by the customer, with a focus on evaluating the product's design and distinguishing between positive aspects and areas for improvement. \n",
    "Identify primary features or attributes of the product that the customer appreciated or highlighted, specifically looking for mentions related to the feel of the keys, sound produced by the keys, overall user experience, charging aspect, and the design of the product, etc. \n",
    "Assess the overall tone of the review (positive, neutral, or negative) based on the sentiment expressed about these attributes. \n",
    "Additionally, provide a detailed evaluation of the design, outline the positive aspects that the customer enjoyed, and note any areas of improvement or disappointment mentioned. \n",
    "Extract the customer's rating of the product on a scale of 1 to 5, as indicated at the beginning of the review. \n",
    "Summarize your findings in a structured JSON format, including an array of keywords, evaluations for design, satisfaction points, improvement areas, the assessed tone, and the numerical rating. \n",
    "\n",
    "INPUT:\n",
    "{input}\n",
    "\n",
    "\"\"\"\n",
    "prompt = ChatPromptTemplate.from_template(prompt_template)\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Chain of Density 요약"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "\n",
    "prompt_title = \"chain-of-density-korean\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"Article: {ARTICLE}\n",
    "You will generate increasingly concise, entity-dense summaries of the above article. \n",
    "\n",
    "Repeat the following 2 steps 5 times. \n",
    "\n",
    "Step 1. Identify 1-3 informative entities (\";\" delimited) from the article which are missing from the previously generated summary. \n",
    "Step 2. Write a new, denser summary of identical length which covers every entity and detail from the previous summary plus the missing entities. \n",
    "\n",
    "A missing entity is:\n",
    "- relevant to the main story, \n",
    "- specific yet concise (100 words or fewer), \n",
    "- novel (not in the previous summary), \n",
    "- faithful (present in the article), \n",
    "- anywhere (can be located anywhere in the article).\n",
    "\n",
    "Guidelines:\n",
    "\n",
    "- The first summary should be long (8-10 sentences, ~200 words) yet highly non-specific, containing little information beyond the entities marked as missing. Use overly verbose language and fillers (e.g., \"this article discusses\") to reach ~200 words.\n",
    "- Make every word count: rewrite the previous summary to improve flow and make space for additional entities.\n",
    "- Make space with fusion, compression, and removal of uninformative phrases like \"the article discusses\".\n",
    "- The summaries should become highly dense and concise yet self-contained, i.e., easily understood without the article. \n",
    "- Missing entities can appear anywhere in the new summary.\n",
    "- Never drop entities from the previous summary. If space cannot be made, add fewer new entities. \n",
    "\n",
    "Remember, use the exact same number of words for each summary.\n",
    "Answer in JSON. The JSON should be a list (length 5) of dictionaries whose keys are \"Missing_Entities\" and \"Denser_Summary\".\n",
    "Use only KOREAN language to reply.\"\"\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Chain of Density (Korean) - 2\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "\n",
    "prompt_title = \"chain-of-density-map-korean\"\n",
    "\n",
    "# 요약문을 작성하기 위한 프롬프트 정의 (직접 프롬프트를 작성하는 경우)\n",
    "prompt = ChatPromptTemplate.from_template(\n",
    "    \"\"\"Article: {ARTICLE}\n",
    "You will generate increasingly concise, entity-dense summaries of the above article. \n",
    "\n",
    "Repeat the following 2 steps 3 times. \n",
    "\n",
    "Step 1. Identify 1-3 informative entities (\";\" delimited) from the article which are missing from the previously generated summary. \n",
    "Step 2. Write a new, denser summary of identical length which covers every entity and detail from the previous summary plus the missing entities. \n",
    "\n",
    "A missing entity is:\n",
    "- relevant to the main story, \n",
    "- specific yet concise (100 words or fewer), \n",
    "- novel (not in the previous summary), \n",
    "- faithful (present in the article), \n",
    "- anywhere (can be located anywhere in the article).\n",
    "\n",
    "Guidelines:\n",
    "\n",
    "- The first summary should be long (8-10 sentences, ~200 words) yet highly non-specific, containing little information beyond the entities marked as missing. Use overly verbose language and fillers (e.g., \"this article discusses\") to reach ~200 words.\n",
    "- Make every word count: rewrite the previous summary to improve flow and make space for additional entities.\n",
    "- Make space with fusion, compression, and removal of uninformative phrases like \"the article discusses\".\n",
    "- The summaries should become highly dense and concise yet self-contained, i.e., easily understood without the article. \n",
    "- Missing entities can appear anywhere in the new summary.\n",
    "- Never drop entities from the previous summary. If space cannot be made, add fewer new entities. \n",
    "\n",
    "Remember, use the exact same number of words for each summary.\n",
    "Answer \"Missing Entities\" and \"Denser_Summary\" as in TEXT format.\n",
    "Use only KOREAN language to reply.\"\"\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## RAG 문서 프롬프트"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_title = \"rag-korean\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "system = \"\"\"당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 주어진 문맥(context) 에서 주어진 질문(question) 에 답하는 것입니다.\n",
    "검색된 다음 문맥(context) 을 사용하여 질문(question) 에 답하세요. 만약, 주어진 문맥(context) 에서 답을 찾을 수 없다면, 답을 모른다면 `주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다` 라고 답하세요.\n",
    "기술적인 용어나 이름은 번역하지 않고 그대로 사용해 주세요. 답변은 한글로 답변해 주세요.\"\"\"\n",
    "\n",
    "human = \"\"\"#Question: \n",
    "{question} \n",
    "\n",
    "#Context: \n",
    "{context} \n",
    "\n",
    "#Answer:\"\"\"\n",
    "\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages([(\"system\", system), (\"human\", human)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt, parent_commit_hash=\"latest\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## RAG + 출처"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.prompts import ChatPromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt_title = \"rag-korean-with-source\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "system = \"\"\"당신은 질문-답변(Question-Answering)을 수행하는 친절한 AI 어시스턴트입니다. 당신의 임무는 주어진 문맥(context) 에서 주어진 질문(question) 에 답하는 것입니다.\n",
    "검색된 다음 문맥(context) 을 사용하여 질문(question) 에 답하세요. 만약, 주어진 문맥(context) 에서 답을 찾을 수 없다면, 답을 모른다면 `주어진 정보에서 질문에 대한 정보를 찾을 수 없습니다` 라고 답하세요.\n",
    "기술적인 용어나 이름은 번역하지 않고 그대로 사용해 주세요. 출처(page, source)를 답변헤 포함하세요. 답변은 한글로 답변해 주세요.\"\"\"\n",
    "\n",
    "human = \"\"\"#Question: \n",
    "{question} \n",
    "\n",
    "#Context: \n",
    "{context} \n",
    "\n",
    "#Answer:\"\"\"\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages([(\"system\", system), (\"human\", human)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hub.push(f\"{PROMPT_OWNER}/{prompt_title}\", prompt, parent_commit_hash=\"latest\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## LLM Evaluation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import PromptTemplate\n",
    "from langchain import hub\n",
    "\n",
    "prompt = PromptTemplate.from_template(\n",
    "    \"\"\"\n",
    "As an LLM evaluator (judge), please assess the LLM's response to the given question. Evaluate the response's accuracy, comprehensiveness, and context precision based on the provided context. After your evaluation, return only the numerical scores in the following format:\n",
    "Accuracy: [score]\n",
    "Comprehensiveness: [score]\n",
    "Context Precision: [score]\n",
    "Final: [normalized score]\n",
    "Grading rubric:\n",
    "\n",
    "Accuracy (0-10 points):\n",
    "Evaluate how well the answer aligns with the information provided in the given context.\n",
    "\n",
    "0 points: The answer is completely inaccurate or contradicts the provided context\n",
    "4 points: The answer partially aligns with the context but contains significant inaccuracies\n",
    "7 points: The answer mostly aligns with the context but has minor inaccuracies or omissions\n",
    "10 points: The answer fully aligns with the provided context and is completely accurate\n",
    "\n",
    "\n",
    "Comprehensiveness (0-10 points):\n",
    "\n",
    "0 points: The answer is completely inadequate or irrelevant\n",
    "3 points: The answer is accurate but too brief to fully address the question\n",
    "7 points: The answer covers main aspects but lacks detail or misses minor points\n",
    "10 points: The answer comprehensively covers all aspects of the question\n",
    "\n",
    "\n",
    "Context Precision (0-10 points):\n",
    "Evaluate how precisely the answer uses the information from the provided context.\n",
    "\n",
    "0 points: The answer doesn't use any information from the context or uses it entirely incorrectly\n",
    "4 points: The answer uses some information from the context but with significant misinterpretations\n",
    "7 points: The answer uses most of the relevant context information correctly but with minor misinterpretations\n",
    "10 points: The answer precisely and correctly uses all relevant information from the context\n",
    "\n",
    "\n",
    "Final Normalized Score:\n",
    "Calculate by summing the scores for accuracy, comprehensiveness, and context precision, then dividing by 30 to get a score between 0 and 1.\n",
    "Formula: (Accuracy + Comprehensiveness + Context Precision) / 30\n",
    "\n",
    "#Given question:\n",
    "{question}\n",
    "\n",
    "#LLM's response:\n",
    "{answer}\n",
    "\n",
    "#Provided context:\n",
    "{context}\n",
    "\n",
    "Please evaluate the LLM's response according to the criteria above. \n",
    "\n",
    "In your output, include only the numerical scores for FINAL NORMALIZED SCORE without any additional explanation or reasoning.\n",
    "ex) 0.81\n",
    "\n",
    "#Final Normalized Score(Just the number):\n",
    "\n",
    "\"\"\"\n",
    ")\n",
    "\n",
    "hub.push(f\"teddynote/context-answer-evaluator\", prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "# 프롬프트\n",
    "system = \"\"\"You are a grader assessing relevance of a retrieved document to a user question. \\n \n",
    "    It does not need to be a stringent test. The goal is to filter out erroneous retrievals. \\n\n",
    "    If the document contains keyword(s) or semantic m   eaning related to the user question, grade it as relevant. \\n\n",
    "    Give a binary score 'yes' or 'no' score to indicate whether the document is relevant to the question.\"\"\"\n",
    "\n",
    "grade_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", system),\n",
    "        (\"human\", \"Retrieved document: \\n\\n {context} \\n\\n User question: {question}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "hub.push(f\"teddynote/retrieval-question-grader\", grade_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "# Prompt\n",
    "system = \"\"\"You are a grader assessing relevance of a retrieved document to the answer. \\n \n",
    "    It does not need to be a stringent test. The goal is to filter out erroneous retrievals. \\n\n",
    "    If the document contains keyword(s) or semantic meaning related to the answer, grade it as relevant. \\n\n",
    "    Give a binary score 'yes' or 'no' score to indicate whether the document is relevant to the answer.\"\"\"\n",
    "\n",
    "grade_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", system),\n",
    "        (\"human\", \"Retrieved document: \\n\\n {context} \\n\\n Answer: {answer}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "hub.push(f\"teddynote/retrieval-answer-grader\", grade_prompt)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py-test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
